package com.huaxin.hxmoduleworkorder.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.huaxin.feignclient.system.SystemClient;
import com.huaxin.feignclient.system.models.ElectricianScopeDTO;
import com.huaxin.feignclient.system.models.Family;
import com.huaxin.feignclient.system.models.Organization;
import com.huaxin.feignclient.system.models.User;
import com.huaxin.hxmoduleworkorder.common.enums.*;
import com.huaxin.hxmoduleworkorder.dto.ResponseCode;
import com.huaxin.hxmoduleworkorder.dto.ResponseResult;
import com.huaxin.hxmoduleworkorder.dto.request.*;
import com.huaxin.hxmoduleworkorder.feignclients.DeviceFeignService;
import com.huaxin.hxmoduleworkorder.mapper.InspectionOrderCustomerMapper;
import com.huaxin.hxmoduleworkorder.mapper.InspectionOrderItemMapper;
import com.huaxin.hxmoduleworkorder.mapper.InspectionOrderMapper;
import com.huaxin.hxmoduleworkorder.mapping.InspectionOrderCustomerMapping;
import com.huaxin.hxmoduleworkorder.mapping.InspectionOrderMapping;
import com.huaxin.hxmoduleworkorder.models.InspectionOrder;
import com.huaxin.hxmoduleworkorder.models.InspectionOrderCustomer;
import com.huaxin.hxmoduleworkorder.service.InspectionOrderCustomerService;
import com.huaxin.hxmoduleworkorder.service.InspectionOrderService;
import com.huaxin.hxmoduleworkorder.service.OrderNotificationService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 巡查工单服务实现类（使用 MapStruct 映射）
 *
 * @author fuai
 * @since 2025-09-02
 */
@Service
@RequiredArgsConstructor
public class InspectionOrderServiceImpl extends ServiceImpl<InspectionOrderMapper, InspectionOrder> implements InspectionOrderService {
    private final ApplicationContext applicationContext;
    private final InspectionOrderMapping mapping;
    private final InspectionOrderMapper mapper;
    private final InspectionOrderCustomerMapping inspectionOrderCustomerMapping;
    private final SystemClient sysFeignService;
    private final InspectionOrderCustomerService inspectionOrderCustomerService;
    private final InspectionOrderCustomerMapper inspectionOrderCustomerMapper;
    private final OrderNotificationService orderNotificationService;
    private final DeviceFeignService deviceFeignService;
    private final InspectionOrderItemMapper inspectionOrderItemMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult<InspectionOrder> create(InspectionOrderCreateReqDTO in) {
        if (in == null) {
            return ResponseResult.parameterError(null, "请求参数不能为空");
        }
        if (StringUtils.isBlank(in.getTitle())) {
            return ResponseResult.parameterError(null, "标题不能为空");
        }
        if (StringUtils.isBlank(in.getAssignedElectricianId())) {
            return ResponseResult.parameterError(null, "负责电工ID不能为空");
        }
        if (in.getExecuteStartTime() == null) {
            return ResponseResult.parameterError(null, "执行开始时间不能为空");
        }
        if (in.getExecuteEndTime() == null) {
            return ResponseResult.parameterError(null, "执行截止时间不能为空");
        }
        if (in.getExecuteEndTime().isBefore(in.getExecuteStartTime())) {
            return ResponseResult.parameterError(null, "执行截止时间不能早于开始时间");
        }
        if (in.getCustomers() == null || in.getCustomers().isEmpty()) {
            return ResponseResult.parameterError(null, "请选择需要巡查的客户");
        }

        // 1. 创建工单

        InspectionOrder entity = mapping.toEntity(in);
        entity.setStatus(InspectionOrderStatus.IN_PROGRESS);
        if (!this.save(entity)) {
            return ResponseResult.failure(ResponseCode.INTERNAL_SERVER_ERROR, "添加失败，请稍后再试！", null);
        }

        // 2. 创建工单通知
        OrderNotificationCreateReqDTO notifyDto = getOrderNotificationCreateReqDTO(entity);
        if (!orderNotificationService.create(notifyDto)) {
            return ResponseResult.failure(ResponseCode.INTERNAL_SERVER_ERROR, "添加工单通知失败，请稍后再试！", null);
        }

        // 3. 创建工单客户关联
        List<InspectionOrderCustomerCreateReqDTO> customerDTOs;
        try {
            customerDTOs = fetchCustomerDetailsFromRemote(in.getCustomers());
        } catch (Exception e) {
            return ResponseResult.failure(ResponseCode.INTERNAL_SERVER_ERROR, "获取客户信息失败，请稍后重试", null);
        }
        customerDTOs.forEach(dto -> dto.setOrderId(entity.getId()));
        if (!inspectionOrderCustomerService.batchCreate(customerDTOs)) {
            return ResponseResult.failure(ResponseCode.INTERNAL_SERVER_ERROR, "添加工单客户失败，请稍后再试！", null);
        }

        return ResponseResult.ok(entity);
    }

    // 提前获取远程数据（无事务）
    private List<InspectionOrderCustomerCreateReqDTO> fetchCustomerDetailsFromRemote(
            List<InspectionOrderCustomerIdDTO> customerIds) {

        List<InspectionOrderCustomerCreateReqDTO> result = new ArrayList<>();
        for (InspectionOrderCustomerIdDTO item : customerIds) {
            InspectionOrderCustomerCreateReqDTO dto = new InspectionOrderCustomerCreateReqDTO();
            dto.setCustomerId(item.getCustomerId());
            dto.setCustomerType(item.getCustomerType());

            if (Objects.equals(item.getCustomerType(), CustomerType.RESIDENTIAL.getCode())) {
                com.huaxin.feignclient.models.ResponseResult<Family> family = sysFeignService.getFamilyById(item.getCustomerId());
                if (family.getCode() == ResponseCode.SUCCESS.getCode()) {
                    dto.setCustomerName(family.getData().getName());
                    dto.setCustomerAddress(family.getData().getAddress());
                    com.huaxin.feignclient.models.ResponseResult<User> user = sysFeignService.getUserInfoById(family.getData().getCreatedBy());
                    if (user.getCode() == ResponseCode.SUCCESS.getCode()) {
                        dto.setCustomerPhone(user.getData().getPhone());
                    }
                }
            } else {
                com.huaxin.feignclient.models.ResponseResult<Organization> org = sysFeignService.getOrganizationById(item.getCustomerId());
                if (org.getCode() == ResponseCode.SUCCESS.getCode()) {
                    dto.setCustomerName(org.getData().getName());
                    dto.setCustomerPhone(org.getData().getAdminTel());
                    dto.setCustomerAddress(org.getData().getAddress());
                }
            }
            result.add(dto);
        }
        return result;
    }

    /**
     * 事务方法：系统自动创建巡检工单
     */
    @Transactional(rollbackFor = Exception.class)
    protected void createAutoOrders(List<InspectionOrderBatchCreateReqDTO> orderDTOs, List<InspectionOrderCustomerCreateReqDTO> orderCustomerDTOs) {
        if (orderDTOs == null || orderDTOs.isEmpty()) {
            return;
        }

        // 1. 保存主工单
        List<InspectionOrder> orderList = orderDTOs.stream()
                .map(mapping::toAutoOrderEntity)
                .collect(Collectors.toList());

        boolean savedOrders = this.saveBatch(orderList);
        if (!savedOrders) {
            throw new RuntimeException("批量保存巡检工单失败");
        }

        // 2. 保存客户关联
        boolean savedLinks = inspectionOrderCustomerService.batchCreate(orderCustomerDTOs);
        if (!savedLinks) {
            throw new RuntimeException("批量保存工单客户关联失败");
        }

        // 3. 发送通知
        for (InspectionOrder order : orderList) {
            OrderNotificationCreateReqDTO notifyDto = getOrderNotificationCreateReqDTO(order);
            orderNotificationService.create(notifyDto);
        }
    }

    private static @NotNull OrderNotificationCreateReqDTO getOrderNotificationCreateReqDTO(InspectionOrder entity) {
        OrderNotificationCreateReqDTO orderNotificationCreateReqDTO = new OrderNotificationCreateReqDTO();
        orderNotificationCreateReqDTO.setOrderType(OrderType.INSPECTION.getCode());
        orderNotificationCreateReqDTO.setOrderId(entity.getId());
        orderNotificationCreateReqDTO.setRecipientId(entity.getAssignedElectricianId());
        orderNotificationCreateReqDTO.setRecipientRole(OrderNotificationRecipientRole.ELECTRICIAN.getCode());
        orderNotificationCreateReqDTO.setNotificationType(OrderNotificationType.APP_PUSH.getCode());
        orderNotificationCreateReqDTO.setContent("您有一个新的巡查任务待处理");
        return orderNotificationCreateReqDTO;
    }

    @Override
    public ResponseResult<InspectionOrder> get(String id) {
        if (StringUtils.isBlank(id)) {
            return ResponseResult.parameterError(null, "ID不能为空");
        }
        InspectionOrder entity = this.getById(id);
        if (entity != null) {
            Map<String, List<InspectionOrderCustomer>> customersByOrderId = this.getCustomersByOrderIds(List.of(id));
            List<InspectionOrderCustomer> orderCustomers = customersByOrderId.getOrDefault(id, List.of());
            List<InspectionOrderCustomerIdDTO> orderCustomerIdDTOs = inspectionOrderCustomerMapping.toOrderCustomerIdDTOs(orderCustomers);
            entity.setCustomers(orderCustomerIdDTOs);
            return ResponseResult.ok(entity);
        } else {
            return ResponseResult.notFound(null, "巡查工单不存在");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult<String> update(InspectionOrderUpdateReqDTO in) {
        if (in == null) {
            return ResponseResult.parameterError(null, "请求参数不能为空");
        }
        if (StringUtils.isBlank(in.getId())) {
            return ResponseResult.parameterError(null, "ID不能为空");
        }
        if (in.getCustomers() == null || in.getCustomers().isEmpty()) {
            return ResponseResult.parameterError(null, "请选择需要巡查的客户");
        }

        InspectionOrder entity = this.getById(in.getId());
        if (entity == null) {
            return ResponseResult.notFound(null, "巡查工单不存在");
        }
        // 1. 更新工单
        mapping.updateEntity(in, entity);
        boolean updated = this.updateById(entity);
        if (!updated) {
            throw new RuntimeException("更新巡检工单失败");
        }

        // 2. 删除工单关联的客户
        boolean deleted = inspectionOrderCustomerService.deleteByOrderId(in.getId());
        if (!deleted) {
            throw new RuntimeException("删除原有客户关联失败");
        }

        // 3. 创建工单客户关联
        List<InspectionOrderCustomerCreateReqDTO> customerDTOs;
        try {
            customerDTOs = fetchCustomerDetailsFromRemote(in.getCustomers());
        } catch (Exception e) {
            return ResponseResult.failure(ResponseCode.INTERNAL_SERVER_ERROR, "获取客户信息失败，请稍后重试", null);
        }
        customerDTOs.forEach(dto -> dto.setOrderId(entity.getId()));
        inspectionOrderCustomerService.batchCreate(customerDTOs); // 失败抛异常，自动回滚

        return ResponseResult.ok("更新成功！");
    }

    @Override
    public ResponseResult<String> delete(String id) {
        if (StringUtils.isBlank(id)) {
            return ResponseResult.parameterError(null, "ID不能为空");
        }
        InspectionOrder entity = this.getById(id);
        if (entity == null) {
            return ResponseResult.notFound(null, "巡查工单不存在");
        }

        // 使用代理调用 removeById，确保事务和 AOP 正常
        boolean removed = applicationContext.getBean(InspectionOrderService.class).removeById(id);
        if (removed) {
            return ResponseResult.ok("删除成功！");
        } else {
            return ResponseResult.failure(ResponseCode.INTERNAL_SERVER_ERROR, "删除失败，请稍后重试", null);
        }
    }

    @Override
    public ResponseResult<Page<InspectionOrder>> pageList(InspectionOrderPageListReqDTO in) {
        if (in == null) {
            return ResponseResult.parameterError(null, "请求参数不能为空");
        }

        Page<InspectionOrder> page = new Page<>(in.getPageNum(), in.getPageSize());
        Page<InspectionOrder> data = mapper.selectPage(
                page,
                in.getTitle(),
                in.getStatus(),
                in.getCustomerType(),
                in.getCustomerId(),
                in.getRoomId(),
                in.getCabinetId(),
                in.getAssignedElectricianId(),
                in.getExecuteStartTime(),
                in.getExecuteEndTime());
        List<InspectionOrder> records = data.getRecords();
        if (records.isEmpty()) {
            return ResponseResult.ok(data); // 空则直接返回
        }

        // 提取所有工单 ID，批量查询对应的 InspectionOrderCustomer 列表
        List<String> orderIds = records.stream()
                .map(InspectionOrder::getId)
                .collect(Collectors.toList());

        Map<String, List<InspectionOrderCustomer>> customersByOrderId = this.getCustomersByOrderIds(orderIds);

        // 填充每个订单的 customers 和详细信息
        for (InspectionOrder item : records) {
            List<InspectionOrderCustomer> orderCustomers = customersByOrderId.getOrDefault(item.getId(), List.of());
            List<InspectionOrderCustomerIdDTO> orderCustomerIdDTOs = inspectionOrderCustomerMapping.toOrderCustomerIdDTOs(orderCustomers);
            item.setCustomers(orderCustomerIdDTOs);
        }
        return ResponseResult.ok(data);
    }

    /**
     * 根据工单 ID 批量查询工单关联的客户信息
     *
     * @param orderIds 工单 ID 列表
     * @return 工单 ID 对应的工单关联客户信息
     */
    private Map<String, List<InspectionOrderCustomer>> getCustomersByOrderIds(List<String> orderIds) {
        LambdaQueryWrapper<InspectionOrderCustomer> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(InspectionOrderCustomer::getOrderId, orderIds);
        List<InspectionOrderCustomer> allOrderCustomers = inspectionOrderCustomerMapper.selectList(wrapper);
        return allOrderCustomers.stream().collect(Collectors.groupingBy(InspectionOrderCustomer::getOrderId));
    }

    @Override
    public ResponseResult<Boolean> exist(String id) {
        if (StringUtils.isBlank(id)) {
            return ResponseResult.parameterError(null, "ID不能为空");
        }
        LambdaQueryWrapper<InspectionOrder> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(InspectionOrder::getId, id);
        return ResponseResult.ok(this.exists(wrapper));
    }

    @Override
    public ResponseResult<Boolean> cancel(String id) {
        if (StringUtils.isBlank(id)) {
            return ResponseResult.parameterError(null, "ID不能为空");
        }
        InspectionOrder entity = this.getById(id);
        if (entity == null) {
            return ResponseResult.notFound(null, "巡查工单不存在");
        }
        if (!InspectionOrderStatus.PUBLISHED.equals(entity.getStatus())) {
            return ResponseResult.failure(ResponseCode.BAD_REQUEST, "当前工单状态不允许取消", null);
        }
        entity.setStatus(InspectionOrderStatus.CANCELLED);
        if (this.updateById(entity)) {
            return ResponseResult.ok(true);
        } else {
            return ResponseResult.failure(ResponseCode.INTERNAL_SERVER_ERROR, "取消失败，请稍后再试！", null);
        }
    }

    @Override
    public ResponseResult<List<Map<String, Object>>> countItemsByRoomIds(List<String> roomIds, String inspectionOrderId) {
        if (roomIds == null || roomIds.isEmpty()) {
            return ResponseResult.ok(null);
        }
        List<Map<String, Object>> inspectionStats = inspectionOrderItemMapper.countItemStatsByRoomIds(roomIds, inspectionOrderId);
        return ResponseResult.ok(inspectionStats);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createInspectionOrders(String frequency, String templateId) {
        LocalDateTime now = LocalDateTime.now();

        // Step 1: 【事务外】获取电工负责范围
        com.huaxin.feignclient.models.ResponseResult<List<ElectricianScopeDTO>> result =
                sysFeignService.electricianScopeList(null);
        if (result.getCode() != ResponseCode.SUCCESS.getCode() || result.getData() == null) {
            throw new RuntimeException("获取电工范围失败，code=" + result.getCode());
        }

        List<ElectricianScopeDTO> scopes = result.getData();
        if (scopes.isEmpty()) {
            return;
        }

        // Step 2: 【事务外】构建所有待创建的工单 DTO 和客户数据
        List<InspectionOrderBatchCreateReqDTO> orderDTOs = new ArrayList<>();
        List<InspectionOrderCustomerCreateReqDTO> customerDTOs = new ArrayList<>();

        for (ElectricianScopeDTO scope : scopes) {

            List<InspectionOrderCustomerIdDTO> customerIds = new ArrayList<>();
            // 收集家庭ID
            if (scope.getFamilyList() != null && !scope.getFamilyList().isEmpty()) {
                List<InspectionOrderCustomerIdDTO> familyCustomerIds = scope.getFamilyList().stream().map(family ->
                        {
                            InspectionOrderCustomerIdDTO dto = new InspectionOrderCustomerIdDTO();
                            dto.setCustomerId(family.getId());
                            dto.setCustomerType(CustomerType.RESIDENTIAL.getCode());
                            return dto;
                        }
                ).toList();
                customerIds.addAll(familyCustomerIds);
            }
            // 收集组织ID
            if (scope.getOrgList() != null && !scope.getOrgList().isEmpty()) {
                List<InspectionOrderCustomerIdDTO> orgCustomerIds = scope.getOrgList().stream().map(org ->
                        {
                            InspectionOrderCustomerIdDTO dto = new InspectionOrderCustomerIdDTO();
                            dto.setCustomerId(org.getId());
                            dto.setCustomerType(CustomerType.COMMERCIAL.getCode());
                            return dto;
                        }
                ).toList();
                customerIds.addAll(orgCustomerIds);
            }

            if (customerIds.isEmpty()) continue;

            String orderId = UUID.randomUUID().toString().replace("-", "");

            // 调用远程服务获取客户详情（事务外）
            List<InspectionOrderCustomerCreateReqDTO> thisCustomerDTOs;
            try {
                thisCustomerDTOs = fetchCustomerDetailsFromRemote(customerIds);
            } catch (Exception e) {
                throw new RuntimeException("获取客户详情失败", e); // 让事务回滚
            }

            if (thisCustomerDTOs.isEmpty()) continue;

            // 构建主工单 DTO
            String title = "【自动】【" + scope.getElectrician().getRealName() + "】" +
                    getFreqTitle(frequency) + "安全巡检 - " +
                    now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
            orderDTOs.add(new InspectionOrderBatchCreateReqDTO()
                    .setTitle(title)
                    .setDescription(getDescription(frequency))
                    .setAssignedElectricianId(scope.getElectrician().getId())
                    .setAssignedElectricianName(scope.getElectrician().getRealName())
                    .setExecuteStartTime(now)
                    .setExecuteEndTime(calculateEndTime(frequency, now))
                    .setTemplateId(templateId)
                    .setCustomers(thisCustomerDTOs)
                    .setId(orderId)

            );

            thisCustomerDTOs.forEach(dto -> dto.setOrderId(orderId));
            customerDTOs.addAll(thisCustomerDTOs);
        }

        if (orderDTOs.isEmpty()) {
            return;
        }
        // Step 3: 【事务内】保存主表 + 设置 orderId + 保存关联表
        createAutoOrders(orderDTOs, customerDTOs);
    }

    private String getFreqTitle(String freq) {
        return switch (freq) {
            case "weekly" -> "周度";
            case "monthly" -> "月度";
            case "quarterly" -> "季度";
            case "annual" -> "年度";
            default -> "未知";
        };
    }

    private String getDescription(String freq) {
        return switch (freq) {
            case "weekly" -> "周度例行安全检查，需在本周内完成。";
            case "monthly" -> "月度例行安全检查，需在本月内完成。";
            case "quarterly" -> "季度全面安全检查，需在本季度内完成。";
            case "annual" -> "年度全面安全检查，需在年内完成。";
            default -> "例行检查";
        };
    }

    private LocalDateTime calculateEndTime(String freq, LocalDateTime now) {
        return switch (freq) {
            case "weekly" -> now.plusDays(7);
            case "monthly" -> now.plusMonths(1).withDayOfMonth(1).minusSeconds(1);
            case "quarterly" -> now.plusMonths(3).withDayOfMonth(1).minusSeconds(1);
            case "annual" -> now.withDayOfYear(now.toLocalDate().lengthOfYear());
            default -> now.plusDays(7);
        };
    }

    //根据企业id查询巡检工单
    @Override
    public ResponseResult<List<InspectionOrder>> queryInspectionOrderByOrgId(String orgId) {
        // 1. 安全校验
        if (orgId == null || orgId.trim().isEmpty()) {
            return ResponseResult.ok(Collections.emptyList());
        }

        // 2. 查询该 orgId（作为 customerId）关联的所有 InspectionOrderCustomer
        LambdaQueryWrapper<InspectionOrderCustomer> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(InspectionOrderCustomer::getCustomerId, orgId);
        List<InspectionOrderCustomer> orderCustomers = inspectionOrderCustomerMapper.selectList(wrapper);

        // 3. 提取所有 orderId
        Set<String> orderIds = orderCustomers.stream()
                .map(InspectionOrderCustomer::getOrderId)
                .filter(Objects::nonNull) // 防止空 ID
                .collect(Collectors.toSet());

        // 4. 如果没有订单 ID，直接返回空
        if (orderIds.isEmpty()) {
            return ResponseResult.ok(Collections.emptyList());
        }

        // 5. 【关键优化】使用 IN 一次性查询所有 InspectionOrder
        List<InspectionOrder> inspectionOrders = this.listByIds(orderIds);

        return ResponseResult.ok(inspectionOrders);
    }

    //根据客户id查询巡检工单数量
    public ResponseResult<Long> queryInspectionOrderCountByCustomerId(String orgId) {
        LambdaQueryWrapper<InspectionOrderCustomer> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(InspectionOrderCustomer::getCustomerId, orgId);
        return ResponseResult.ok(inspectionOrderCustomerMapper.selectCount(wrapper));
    }
}